# coding:utf-8

import numpy as np
import cv2
from typing import Tuple, List
import PIL
from PIL import Image
Image.MAX_IMAGE_PIXELS = None
import os


class DictToObject:
    def __init__(self, dictionary):
        for key, value in dictionary.items():
            if isinstance(value, dict):
                setattr(self, key, DictToObject(value))
            else:
                setattr(self, key, value)


#+++++++++++++++++++++++++++++++++++++++++++++++++ functions ++++++++++++++++++++++++++++++++++++++++++++++++++++#
def image2bits(image: Image or np.ndarray):
    """return bits: np.ndarray, shape"""
    assert type(image) in [PIL.PngImagePlugin.PngImageFile, PIL.Image.Image, np.ndarray]
    image = np.asarray(image, dtype=np.uint8) if not isinstance(image, np.ndarray) else image.astype(np.uint8)
    flat = image.flatten()
    bits = np.unpackbits(flat)
    return bits, image.shape


def bits2image(bits, shape):
    """return PIL.Image"""
    bytes_ = np.packbits(bits)
    bytes_ = bytes_[:np.prod(shape)]
    image = np.reshape(bytes_, shape)
    return Image.fromarray(image.astype(np.uint8))


def img_bit(image: Image or np.ndarray,
            suffix: str = ".png"):
    """bit_all: str"""
    assert type(image) in [PIL.PngImagePlugin.PngImageFile, PIL.Image.Image, np.ndarray]
    image_array = np.asarray(image) if not isinstance(image, np.ndarray) else image
    success, buffer = cv2.imencode(suffix, image_array)
    if success:
        file_context = buffer.tobytes()
    else:
        raise ValueError("The cv2.imencode likely has problem.")
    tmp_a = []
    bit_all = ''
    for i in file_context:
        tmp_a.append(i)
    tmp_b = np.array(tmp_a, dtype=np.uint8)
    for j in tmp_b:
        k = bin(j).replace("0b", '').rjust(8, '0')
        bit_all = bit_all + k
    return bit_all


def cut_string(obj, sec):
    """
    切割字符串
    :param obj: 输入字符串
    :param sec: 切割的位数
    :return: 切割后的字符串
    """
    return [obj[i:i + sec] for i in range(0, len(obj), sec)]


def bit_to_img(string):
    """
    :param string: 图片比特流字符串
    :param output_path: 输出图片文件夹路径
    :return: out_stream
    """
    split_char = cut_string(string, 8)  # 字符串按8切割
    # int(a, 2)表示将二进制的字符串a表示为十进制的int
    int_8 = [int(a, 2) for a in split_char]  # 字符串转换为int类型的数据
    out_stream = np.array(int_8, dtype=np.uint8)
    # out_stream.tofile(output_path)
    return out_stream


def get_bitarray(bit_string: str):
    k_char = cut_string(bit_string, 1)
    k = [int(a, 2) for a in k_char]
    bit_array = np.array(k)
    return bit_array


